﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Reporting.WinForms.Internal.Soap.ReportingServices2005.Execution;
using SSRSTestGenerator.Models;
using SSRSTestGenerator.Resources;
using System.Text.RegularExpressions;
using System.Windows.Input;


namespace SSRSTestGenerator.UserControls
{
    /// <summary>
    /// Interaction logic for BuildAssertions.xaml
    /// </summary>
    public partial class BuildAssertions : UserControl
    {
        #region Setters & Getters
        public delegate void EditProject();
        public event EditProject EditedProject;

        public delegate void UPdateClassPropsWithNodeDetails(object sender, NodeDetails arg);
        public event UPdateClassPropsWithNodeDetails UpdatedClassPropsWithNodeDetails;

        public delegate void NotifyUser(object sender, NotificationArgs arg);
        public event NotifyUser NotifyedUser;

        public delegate void CreateTests(object sender, TestCodeArgs arg);
        public event CreateTests CreatedTests;

        public delegate void AssertionAction(object sender, bool addToCounter);
        public event AssertionAction AssertionActioned;

        public delegate void RibbonBarItemUpdate(object sender, List<RibbonMenuItemArgs> arg);
        public event RibbonBarItemUpdate RibbonBarItemUpdated;

        App MainApp { get; set; }

        private XmlDocument reportXmlDoc = null;
        public XmlDocument ReportXmlDoc
        {
            get { return reportXmlDoc; }
            set { reportXmlDoc = value; }
        }

        private List<NodeDetails> lstNodeDetails = null;
        public List<NodeDetails> LstNodeDetails
        {
            get { return lstNodeDetails; }
            set { lstNodeDetails = value; }
        }

        private SSRSTestGenerator.Models.ClassEnumerations.TestFrameworks testFramework = ClassEnumerations.TestFrameworks.NUnit;
        public SSRSTestGenerator.Models.ClassEnumerations.TestFrameworks TestFramework
        {
            get { return testFramework; }
            set
            {

                testFramework = value;
                this.UpdateAssertionDropdownList();
            }
        }

        private SSRSTestGenerator.Models.ClassEnumerations.CodeLanguages language = ClassEnumerations.CodeLanguages.CSharp;
        public SSRSTestGenerator.Models.ClassEnumerations.CodeLanguages Language
        {
            get { return this.language; }
            set { this.language = value; }
        }

        private string reportName = string.Empty;
        public string ReportName
        {
            get { return reportName; }
            set { reportName = value.Replace(" ", "_"); ; }
        }

        private string reportPath = string.Empty;
        public string ReportPath
        {
            get { return reportPath; }
            set { reportPath = value; }
        }

        private string projectName = string.Empty;
        public string ProjectName
        {
            get { return this.projectName; }
            set { this.projectName = value.Replace(" ", "_"); }
        }

        private string classFolder = string.Empty;
        public string ClassFolder
        {
            get { return this.classFolder; }
            set
            {
                string updatedValue = value.Replace("/", "");
                this.classFolder = "." + updatedValue;
            }
        }

        private string reportingServiceUrl = string.Empty;
        public string ReportingServiceUrl
        {
            get { return reportingServiceUrl; }
            set { reportingServiceUrl = value; }
        }

        private ParameterValue[] parameters = null;
        public ParameterValue[] Parameters
        {
            get { return this.parameters; }
            set { this.parameters = value; }
        }

        private string className = string.Empty;
        public string ClassName
        {
            get { return this.className; }
            set
            {
                this.className = value;                
            }
        }
        #endregion

        #region Private variables
        private List<NodeIndex> lstNodeIndex = null;
        List<RibbonMenuItemArgs> MenuArgs { get; set; }
        #endregion

        public BuildAssertions()
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                InitializeComponent();

                this.MainApp = ((App)Application.Current); // reference to logging
                this.MainApp.LogMessage("Info","BuildAssertions entered");

                this.LstNodeDetails = new List<NodeDetails>();
                this.MenuArgs = new List<RibbonMenuItemArgs>();
                this.lstNodeIndex = new List<NodeIndex>();
                this.ClassFolder = System.Configuration.ConfigurationManager.AppSettings["ProjectClassSubFolder"]; // subfolder to main project - will always have this structure
            }
            finally {
                this.MainApp.LogMessage("Info","BuildAssertions exited");
                Mouse.OverrideCursor = null; }
        }

        #region Class Evenst
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                this.MainApp.LogMessage("Info","UserControl_Loaded entered");                
            }
            finally
            {
                this.MainApp.LogMessage("Info","UserControl_Loaded exited");
            }
        }
        private void trViewReportXml_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","trViewReportXml_SelectedItemChanged entered");

                bdrAssertion.Visibility = System.Windows.Visibility.Visible;

                TreeViewItem item = (TreeViewItem)trViewReportXml.SelectedItem;

                if (item == null) return;

                NodeDetails details = (NodeDetails)item.Tag;
                if (details == null)
                {
                    this.cboElements.ItemsSource = null;
                    lstBoxAssertions.Items.Clear();
                    return;
                }

                this.cboElements.ItemsSource = details.Attributes; // set elements combo

                lstBoxAssertions.Items.Clear();
                foreach (NodeAssertions assert in details.Assertions)
                {
                    ListBoxItem lstItem = new ListBoxItem();
                    lstItem.Content = assert.ListBoxValueOfAssertion;
                    lstItem.Tag = assert;
                    lstBoxAssertions.Items.Add(lstItem);
                }

                this.btnUpdate.Visibility = System.Windows.Visibility.Collapsed;
                this.btnAdd.Visibility = System.Windows.Visibility.Visible;
                this.btnDelete.Visibility = System.Windows.Visibility.Collapsed;
            }
            finally {
                this.MainApp.LogMessage("Info","trViewReportXml_SelectedItemChanged exited");
                Mouse.OverrideCursor = null; }
        }
        private void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","btnAdd_Click entered");

                // update ribbon menu 
                this.MenuArgs.Clear();
                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnReportCreateTests", IsRibbonButtonEnabled = true });
                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnSave", IsRibbonButtonEnabled = true });
                this.RibbonBarItemUpdated(this, MenuArgs);

                // add assertion to class(es)            
                string assertString = this.cboElements.SelectedValue.ToString() + " " + ((Assertions)(this.cboAssertions.SelectedItem)).AssertionName + " ";
                assertString += this.txtBxValue.IsEnabled ? this.txtBxValue.Text : string.Empty;

                TreeViewItem item = (TreeViewItem)trViewReportXml.SelectedItem;
                NodeDetails details = (NodeDetails)item.Tag;
                this.LstNodeDetails.Remove(details); // remove the old node class

                NodeAssertions assertNode = null;
                if (TestFramework == ClassEnumerations.TestFrameworks.VSTest)
                {
                    assertNode = new NodeAssertions() { clsAssertion = (Assertions)this.cboAssertions.SelectedItem, Assertion = this.cboAssertions.SelectedIndex, Attribute = this.cboElements.SelectedValue.ToString(), Value = this.txtBxValue.IsEnabled ? this.txtBxValue.Text : string.Empty, ListBoxValueOfAssertion = assertString };
                }
                else
                {
                    assertNode = new NodeAssertions() { clsAssertion = (Assertions)this.cboAssertions.SelectedItem, Assertion = this.cboAssertions.SelectedIndex, Attribute = this.cboElements.SelectedValue.ToString(), Value = this.txtBxValue.IsEnabled ? this.txtBxValue.Text : string.Empty, ListBoxValueOfAssertion = assertString };
                }
                details.Assertions.Add(assertNode);
                item.Tag = details;
                this.LstNodeDetails.Add(details); // add the newly added node class

                ListBoxItem assertionItem = new ListBoxItem();
                assertionItem.Content = assertString;
                assertionItem.Tag = assertNode;
                lstBoxAssertions.Items.Add(assertionItem);

                // add node details to the class properties
                this.UpdatedClassPropsWithNodeDetails(this, details);

                this.txtBxValue.Text = string.Empty;
                this.cboElements.SelectedIndex = this.cboAssertions.SelectedIndex = -1;
                
                this.AssertionActioned(this, true); // update class and project test counter                
            }
            finally {
                this.MainApp.LogMessage("Info","btnAdd_Click exited");
                Mouse.OverrideCursor = null; }
        }
        private void btndelete_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","btndelete_Click entered");

                // remove from listbox
                ListBoxItem itemListBx = (ListBoxItem)this.lstBoxAssertions.SelectedItem;
                NodeAssertions itemTag = (NodeAssertions)itemListBx.Tag;

                this.lstBoxAssertions.Items.RemoveAt(lstBoxAssertions.Items.IndexOf(lstBoxAssertions.SelectedItem));

                // ribbon bar
                if (this.lstBoxAssertions.Items.Count == 0)
                {
                    // update ribbon menu 
                    this.MenuArgs.Clear();
                    this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnReportCreateTests", IsRibbonButtonEnabled = false });
                    this.RibbonBarItemUpdated(this, MenuArgs);
                }

                // xml treeview
                TreeViewItem itemTree = (TreeViewItem)trViewReportXml.SelectedItem;
                NodeDetails details = (NodeDetails)itemTree.Tag;
                // find old assertion & remove it - then add new assertion
                details.Assertions.Remove(itemTag);
                ((TreeViewItem)trViewReportXml.SelectedItem).Tag = details;

                this.cboElements.SelectedIndex = -1;
                this.cboAssertions.SelectedIndex = -1;
                this.txtBxValue.Text = string.Empty;
                this.lstBoxAssertions.SelectedIndex = -1;

                this.btnUpdate.Visibility = System.Windows.Visibility.Collapsed;
                this.btnDelete.Visibility = System.Windows.Visibility.Collapsed;
                this.btnAdd.Visibility = System.Windows.Visibility.Visible;

                this.EditedProject();  //project has been edited

                this.AssertionActioned(this, false); // update class and project test counter                
            }
            finally {
                this.MainApp.LogMessage("Info","btndelete_Click exited");
                Mouse.OverrideCursor = null; }
        }
        private void lstBoxAssertions_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","lstBoxAssertions_SelectionChanged entered");

                bdrAssertion.Visibility = System.Windows.Visibility.Visible;

                ListBoxItem assertionItem = (ListBoxItem)this.lstBoxAssertions.SelectedItem;
                if (assertionItem != null)
                {
                    NodeAssertions details = (NodeAssertions)assertionItem.Tag;
                    // this.cboAssertions.Text = details.Assertion.ToString();
                    try
                    {
                        this.cboAssertions.SelectedIndex = int.Parse(details.Assertion.ToString());
                    }
                    catch (Exception) { this.cboAssertions.Text = details.Assertion.ToString(); }
                    this.cboElements.SelectedValue = details.Attribute.ToString();
                    this.txtBxValue.Text = details.Value;

                    this.btnUpdate.Visibility = System.Windows.Visibility.Visible;
                    this.btnAdd.Visibility = System.Windows.Visibility.Collapsed;
                    this.btnDelete.Visibility = System.Windows.Visibility.Visible;
                }
            }
            finally {
                this.MainApp.LogMessage("Info","lstBoxAssertions_SelectionChanged exited");
                Mouse.OverrideCursor = null; }
        }
        public void BuildTreeTabSelected(string xml, string className)
        {
            try
            {                
                this.MainApp.LogMessage("Info","BuildTreeTabSelected entered");

                this.ClassName = className; // currently selected tree node
                this.MenuArgs.Clear();            
                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnReportCreateTests", IsRibbonButtonEnabled = this.LstNodeDetails.Count > 0 });
                this.RibbonBarItemUpdated(this, MenuArgs);

                if (String.IsNullOrEmpty(xml))
                {                    
                    this.trViewReportXml.Items.Clear();
                    this.lstBoxAssertions.Items.Clear();
                    this.buildAsertGrid.IsEnabled = false;
                    return;
                }

                this.buildAsertGrid.IsEnabled = true;
                this.ReportXmlDoc = new XmlDocument();
                var dom = new XmlDocument();
                dom.LoadXml(xml);
                var loaded = new XDocument();
                if (dom.DocumentElement != null)
                {
                    if (dom.DocumentElement.NamespaceURI != String.Empty)
                    {
                        dom.LoadXml(dom.OuterXml.Replace(dom.DocumentElement.NamespaceURI, String.Empty));
                        dom.DocumentElement.RemoveAllAttributes();
                        loaded = XDocument.Parse(dom.OuterXml);
                        this.ReportXmlDoc.LoadXml(loaded.ToString()); //laod xml without namespaces    
                    }
                    else
                    {
                        this.ReportXmlDoc.LoadXml(xml); //laod xml as normal
                    }
                }
                else
                {
                    return;
                }

                this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - Building Xml tree...", ImagePath = "/Images/16x16-Information.png" });

                this.BuildTree(this.trViewReportXml, loaded, className);                
            }
            finally { this.MainApp.LogMessage("Info","BuildTreeTabSelected exited"); }
        }       
        private void btnUpdate_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","btnUpdate_Click entered");

                // item about to be updated in listbox
                ListBoxItem itemListBx = (ListBoxItem)this.lstBoxAssertions.SelectedItem;
                NodeAssertions itemTag = (NodeAssertions)itemListBx.Tag;

                // update listbox

                string assertString = string.Empty;
                if (TestFramework == ClassEnumerations.TestFrameworks.VSTest)
                {
                    assertString = this.cboElements.SelectedValue.ToString() + " " + (MSAssertions)Enum.Parse(typeof(MSAssertions), ((SSRSTestGenerator.Models.Assertions)(this.cboAssertions.SelectionBoxItem)).AssertionName) + " " + this.txtBxValue.Text;
                    ((ListBoxItem)this.lstBoxAssertions.SelectedItem).Content = this.cboElements.SelectedValue.ToString() + " " + (MSAssertions)Enum.Parse(typeof(MSAssertions), ((SSRSTestGenerator.Models.Assertions)(this.cboAssertions.SelectionBoxItem)).AssertionName) + " " + this.txtBxValue.Text; ;
                    ((ListBoxItem)this.lstBoxAssertions.SelectedItem).Tag = new NodeAssertions() { clsAssertion = (Assertions)this.cboAssertions.SelectedValue, Assertion = (MSAssertions)Enum.Parse(typeof(MSAssertions), ((SSRSTestGenerator.Models.Assertions)(this.cboAssertions.SelectionBoxItem)).AssertionName), Attribute = this.cboElements.SelectedValue.ToString(), Value = this.txtBxValue.Text, ListBoxValueOfAssertion = assertString }; ;
                }
                else
                {
                    assertString = this.cboElements.SelectedValue.ToString() + " " + (SSRSTestGenerator.Models.NUnitAssertions)Enum.Parse(typeof(SSRSTestGenerator.Models.NUnitAssertions), ((SSRSTestGenerator.Models.Assertions)(this.cboAssertions.SelectionBoxItem)).AssertionName) + " " + this.txtBxValue.Text;
                    ((ListBoxItem)this.lstBoxAssertions.SelectedItem).Content = this.cboElements.SelectedValue.ToString() + " " + (SSRSTestGenerator.Models.NUnitAssertions)Enum.Parse(typeof(SSRSTestGenerator.Models.NUnitAssertions), ((SSRSTestGenerator.Models.Assertions)(this.cboAssertions.SelectionBoxItem)).AssertionName) + " " + this.txtBxValue.Text; ;
                    ((ListBoxItem)this.lstBoxAssertions.SelectedItem).Tag = new NodeAssertions() { clsAssertion = (Assertions)this.cboAssertions.SelectedValue, Assertion = (SSRSTestGenerator.Models.NUnitAssertions)Enum.Parse(typeof(SSRSTestGenerator.Models.NUnitAssertions), ((SSRSTestGenerator.Models.Assertions)(this.cboAssertions.SelectionBoxItem)).AssertionName), Attribute = this.cboElements.SelectedValue.ToString(), Value = this.txtBxValue.Text, ListBoxValueOfAssertion = assertString }; ;
                }

                // xml treeview
                TreeViewItem itemTree = (TreeViewItem)trViewReportXml.SelectedItem;
                NodeDetails details = (NodeDetails)itemTree.Tag;

                // find old assertion & remove it - then add new assertion
                details.Assertions.Remove(itemTag);

                if (TestFramework == ClassEnumerations.TestFrameworks.VSTest)
                {                    
                    details.Assertions.Add(new NodeAssertions() { clsAssertion = (Assertions)this.cboAssertions.SelectedItem, Assertion = this.cboAssertions.SelectedIndex, Attribute = this.cboElements.SelectedValue.ToString(), Value = this.txtBxValue.IsEnabled ? this.txtBxValue.Text : string.Empty, ListBoxValueOfAssertion = assertString });
                }
                else
                {                 
                    details.Assertions.Add(new NodeAssertions() { clsAssertion = (Assertions)this.cboAssertions.SelectedItem, Assertion = this.cboAssertions.SelectedIndex, Attribute = this.cboElements.SelectedValue.ToString(), Value = this.txtBxValue.IsEnabled ? this.txtBxValue.Text : string.Empty, ListBoxValueOfAssertion = assertString });
                }
            
                ((TreeViewItem)trViewReportXml.SelectedItem).Tag = details;

                this.cboElements.SelectedIndex = -1;
                this.cboAssertions.SelectedIndex = -1;
                this.txtBxValue.Text = string.Empty;
                this.lstBoxAssertions.SelectedIndex = -1;

                this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - Assertion updated successfully", ImagePath = "/Images/16x16-Valid.png" });
                this.EditedProject();  //project has been edited

                // update ribbon
                this.MenuArgs.Clear();
                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnReportCreateTests", IsRibbonButtonEnabled = true });
                this.RibbonBarItemUpdated(this, MenuArgs);

            }
            finally {
                this.MainApp.LogMessage("Info","btnUpdate_Click exited");
                Mouse.OverrideCursor = null; }
        }        
        public void GenerateCode()
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","GenerateCode entered");

                // loop through tree nodes and get tag classes and build up test methods for each assertion

                TestCodeArgs args = new TestCodeArgs(ParseNode());
                CreatedTests(this, args);

                this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - Generating test code...", ImagePath = "/Images/16x16-Information.png" });

                this.EditedProject();  //project has been edited
            }
            finally {
                this.MainApp.LogMessage("Info","GenerateCode exited");
                Mouse.OverrideCursor = null; }
        }
        private void trViewReportXml_GotFocus(object sender, RoutedEventArgs e)
        {
            try
            {
                this.MainApp.LogMessage("Info","trViewReportXml_GotFocus entered");

                this.btnUpdate.Visibility = System.Windows.Visibility.Collapsed;
                this.btnDelete.Visibility = System.Windows.Visibility.Collapsed;
                this.btnAdd.Visibility = System.Windows.Visibility.Visible;
            }
            finally
            {
                this.MainApp.LogMessage("Info","trViewReportXml_GotFocus exited");
            }
        }
        private bool ValidateNewAssertion(string element, string value, object assertions)
        {
            try
            {
                this.MainApp.LogMessage("Info","ValidateNewAssertion entered");

                if (String.IsNullOrEmpty(element) || String.IsNullOrEmpty(value) || assertions == null) return false;
                else return true;
            }
            finally
            {
                this.MainApp.LogMessage("Info","ValidateNewAssertion exited");
            }

        }
        private void lstBoxAssertions_GotFocus(object sender, RoutedEventArgs e)
        {

            try
            {
                this.MainApp.LogMessage("Info","lstBoxAssertions_GotFocus entered");

                if (lstBoxAssertions.SelectedItems.Count > 0)
                {
                    this.btnUpdate.Visibility = System.Windows.Visibility.Visible;
                    this.btnAdd.Visibility = System.Windows.Visibility.Collapsed;
                    this.btnDelete.Visibility = System.Windows.Visibility.Visible;
                }
            }
            finally
            {
                this.MainApp.LogMessage("Info","lstBoxAssertions_GotFocus exited");
            }
        }
        #endregion

        #region Private Methods
        private void UpdateAssertionDropdownList()
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","UpdateAssertionDropdownList entered");

                List<Assertions> lstAssertions = new List<Assertions>();
                this.cboAssertions.ItemsSource = null;                

                if (this.TestFramework == ClassEnumerations.TestFrameworks.VSTest)
                {
                    lstAssertions.Add(new Assertions() { AssertionName = MSTestAssertions.AreEqual, IsAssertionNeedingRegex = false, AssertMemberName = "Assert." });
                    lstAssertions.Add(new Assertions() { AssertionName = MSTestAssertions.AreNotEqual, IsAssertionNeedingRegex = false, AssertMemberName = "Assert." });
                    lstAssertions.Add(new Assertions() { AssertionName = MSTestAssertions.Contains, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = MSTestAssertions.DoesNotMatch, IsAssertionNeedingRegex = true, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = MSTestAssertions.EndsWith, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = MSTestAssertions.Matches, IsAssertionNeedingRegex = true, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = MSTestAssertions.StartsWith, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                }
                else
                {
                    lstAssertions.Add(new Assertions() { AssertionName = SSRSTestGenerator.Resources.NUnitAssertions.AreEqualIgnoringCase, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = SSRSTestGenerator.Resources.NUnitAssertions.AreNotEqualIgnoringCase, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = SSRSTestGenerator.Resources.NUnitAssertions.Contains, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = SSRSTestGenerator.Resources.NUnitAssertions.DoesNotContain, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = SSRSTestGenerator.Resources.NUnitAssertions.DoesNotEndWith, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = SSRSTestGenerator.Resources.NUnitAssertions.DoesNotStartWith, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = SSRSTestGenerator.Resources.NUnitAssertions.EndsWith, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                    lstAssertions.Add(new Assertions() { AssertionName = SSRSTestGenerator.Resources.NUnitAssertions.StartsWith, IsAssertionNeedingRegex = false, AssertMemberName = "StringAssert." });
                }
                this.cboAssertions.ItemsSource = lstAssertions;
            }
            finally {
                this.MainApp.LogMessage("Info","UpdateAssertionDropdownList exited");
                Mouse.OverrideCursor = null; }
        }
        private void BuildTree(TreeView treeView, XDocument doc, string className)
        {
            try
            {
                this.MainApp.LogMessage("Info","BuildTree entered");

                treeView.Items.Clear();

                TreeViewItem treeNode = new TreeViewItem
                {
                    //Should be Root
                    Header = doc.Root.Name.LocalName,
                    IsExpanded = true
                };

                treeView.Items.Add(treeNode);
                this.BuildNodes(treeNode, doc.Root, className);

                this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - Built Xml tree", ImagePath = "/Images/16x16-Valid.png" });
            }
            finally { this.MainApp.LogMessage("Info","BuildTree exited"); }
        }
        private void BuildNodes(TreeViewItem treeNode, XElement element, string className)
        {
            try
            {
                this.MainApp.LogMessage("Info","BuildNodes entered");

                NodeDetails nodeDetails = null;
                NodeIndex nodeIndex = null;
                TreeViewItem childTreeNode = null;
                string nodeContents = string.Empty;

                foreach (XNode child in element.Nodes())
                {
                    switch (child.NodeType)
                    {
                        case XmlNodeType.Element:
                            XElement childElement = child as XElement;
                            nodeDetails = new NodeDetails() { Attributes = new List<string>(), Assertions = new List<NodeAssertions>(), NodeIndex = 0, ClassName = className, NodeName = childElement.Name.LocalName };

                            nodeContents = "<" + childElement.Name.LocalName + " ";
                            if (childElement.Attributes().Count() > 0)
                            {
                                if (lstNodeIndex.Count(node => node.NodeName == childElement.Name.LocalName) == 0)
                                {
                                    nodeIndex = new NodeIndex() { NodeName = childElement.Name.LocalName, CurrentIndex = 0 };
                                    lstNodeIndex.Add(nodeIndex);
                                }
                                else
                                {
                                    nodeIndex = lstNodeIndex.Where(node => node.NodeName == childElement.Name.LocalName).FirstOrDefault();
                                    lstNodeIndex.Where(node => node.NodeName == childElement.Name.LocalName).FirstOrDefault().CurrentIndex++;
                                    nodeIndex.CurrentIndex++;
                                }

                                nodeDetails.NodeIndex = nodeIndex.CurrentIndex;
                                nodeDetails.NodeName = childElement.Name.LocalName;


                                foreach (XAttribute attribute in childElement.Attributes())
                                {
                                    nodeContents += attribute.Name + " = " + attribute.Value + ", ";
                                    nodeDetails.Attributes.Add(attribute.Name.ToString());
                                }

                                nodeContents = nodeContents.Remove(nodeContents.Length - 2, 1);

                                // get the xpath                            
                                nodeDetails.XPath = childElement.GetAbsoluteXPath();
                            }

                            nodeContents += ">";
                            childTreeNode = new TreeViewItem
                            {
                                Header = nodeContents,                                
                                Tag = RetrieveExistingNodeDetails(nodeDetails.XPath, nodeDetails),
                                ToolTip = nodeDetails.XPath,
                                IsExpanded = true
                            };

                            treeNode.Items.Add(childTreeNode);
                            this.BuildNodes(childTreeNode, childElement, className);
                            break;
                    }
                }
            }
            finally { this.MainApp.LogMessage("Info","BuildNodes exited"); }
        }
        private string CleanMethodName(string strIn)
        {
            try
            {
                this.MainApp.LogMessage("Info","CleanMethodName entered");                 
                return Regex.Replace(strIn, @"[^\w]", ""); // Replace any character that is not an alphanumeric character, with empty strings
            }
            finally
            {
                this.MainApp.LogMessage("Info","CleanMethodName exited"); 
            }
        }
        private string AssertionName(object assertInteger)
        {
            try
            {
                this.MainApp.LogMessage("Info","AssertionName entered"); 

                int assertIntValue;

                try
                {
                    assertIntValue = int.Parse(assertInteger.ToString());
                }
                catch (Exception) { return assertInteger.ToString(); }


                List<Assertions> lstAssertions = new List<Assertions>();
                lstAssertions = (List<Assertions>)this.cboAssertions.ItemsSource;

                return lstAssertions[assertIntValue].AssertionName;
            }
            finally
            {
                this.MainApp.LogMessage("Info","AssertionName exited"); 
            }
        }
        private string ParseNode()
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","ParseNode entered"); 

                string runningMethodCode = string.Empty, methodName = string.Empty, nameSpace = string.Empty;

                // get the localised template and string format it            
                string strClassCode = string.Empty, classMethod = string.Empty, assertionClassMethod = string.Empty;
                StringBuilder methodCode = new StringBuilder();
                StringBuilder classCode = new StringBuilder();
                string folder = string.Empty;
                string assertionMethodName = string.Empty;

                if (TestFramework == ClassEnumerations.TestFrameworks.VSTest)
                {
                    strClassCode = LocalisedStrings.VSTestClassTemplate;
                    classMethod = LocalisedStrings.VSTestMethodTemplate;
                    folder = SSRSTestGenerator.Models.ClassEnumerations.CodeLanguages.CSharp.ToString();
                }
                else
                {
                    strClassCode = LocalisedStrings.NunitClassTemplate;
                    classMethod = LocalisedStrings.NUnitTestMethodTemplate;
                    folder = SSRSTestGenerator.Models.ClassEnumerations.CodeLanguages.VB.ToString();
                }

                ItemCollection items = this.trViewReportXml.Items;
                methodCode = new StringBuilder();                
                foreach (NodeDetails node in this.LstNodeDetails)
                {
                    // does the nodedetail belong to the selected class of code tests
                    if (node.ClassName != this.ClassName) continue;

                    if (node.Assertions.Count > 0)
                    {
                        foreach (NodeAssertions assert in node.Assertions)
                        {
                            string tempMethodCode = classMethod;
                            methodName = string.Empty;
                            methodName = assert.Attribute + "_" + this.AssertionName(assert.Assertion);                           
                            methodName += assert.Value.Trim() == string.Empty ? "" : "_" + assert.Value.Trim();
                            methodName = this.CleanMethodName(methodName);

                            if (methodCode.ToString().Contains(methodName)) methodName += "_" + Guid.NewGuid(); // make method name unique
                            
                            runningMethodCode = string.Empty;
                            string value = assert.clsAssertion.IsAssertionNeedingRegex ? "new Regex(@\"" + assert.Value + "\")" : assert.Value;
                            if (assert.clsAssertion.IsAssertionNeedingRegex)
                            {
                                if (TestFramework == ClassEnumerations.TestFrameworks.NUnit && (assert.clsAssertion.AssertionName.ToLower() == "contains" || assert.clsAssertion.AssertionName.ToLower() == "endswith" || assert.clsAssertion.AssertionName.ToLower() == "startswith"))
                                {                                    
                                    runningMethodCode += assert.clsAssertion.AssertMemberName + this.AssertionName(assert.Assertion) + "(\"" + value + "\", this.reportXml.SelectSingleNode(\"" + node.XPath + "/@" + assert.Attribute + "\").Value);";
                                }
                                else
                                {
                                    runningMethodCode += assert.clsAssertion.AssertMemberName + this.AssertionName(assert.Assertion) + "(this.reportXml.SelectSingleNode(\"" + node.XPath + "/@" + assert.Attribute + "\").Value, " + value + ");";
                                }
                            }
                            else
                            {
                                // runningMethodCode += assert.clsAssertion.AssertMemberName + this.AssertionName(assert.Assertion) + "(this.reportXml.SelectSingleNode(\"" + node.XPath + "/@" + assert.Attribute + "\").Value, \"" + value + "\");";

                                if (TestFramework == ClassEnumerations.TestFrameworks.NUnit && (assert.clsAssertion.AssertionName.ToLower() == "contains" || assert.clsAssertion.AssertionName.ToLower() == "endswith" || assert.clsAssertion.AssertionName.ToLower() == "startswith"))                                
                                {
                                    runningMethodCode += assert.clsAssertion.AssertMemberName + this.AssertionName(assert.Assertion) + "(\"" + value + "\", this.reportXml.SelectSingleNode(\"" + node.XPath + "/@" + assert.Attribute + "\").Value);";                                    
                                }
                                else
                                {
                                    runningMethodCode += assert.clsAssertion.AssertMemberName + this.AssertionName(assert.Assertion) + "(this.reportXml.SelectSingleNode(\"" + node.XPath + "/@" + assert.Attribute + "\").Value, \"" + value + "\");";
                                }
                            }

                            tempMethodCode = String.Format(tempMethodCode, methodName, runningMethodCode);
                            methodCode.Append(tempMethodCode);
                        }
                    }
                }

                // build parameter results
                string templateReportParameters = LocalisedStrings.ReportParameters;
                StringBuilder sbParameters = new StringBuilder();
                int counter = 0;
                if (this.Parameters.Count() > 0)
                {
                    string paramerInstaniate = "\t\tthis.parameters = new ParameterValue[" + (this.Parameters.Count()).ToString() + "];" + Environment.NewLine;
                    sbParameters.Append(paramerInstaniate);

                    foreach (ParameterValue rptParam in this.Parameters)
                    {
                        string runningParameters = templateReportParameters;
                        runningParameters = String.Format(runningParameters, counter.ToString(), rptParam.Name, rptParam.Value);
                        sbParameters.Append(runningParameters);
                        counter++;
                    }
                }
                else
                {
                    sbParameters.Append("this.parameters = new ParameterValue[0];");
                    // sbParameters.Append("this.parameters = new Microsoft.Reporting.WinForms.Internal.Soap.ReportingServices2005.Execution.ParameterValue[0];");
                }
                
                classCode.Append(String.Format(strClassCode, this.ProjectName + this.ClassFolder, this.ReportName, this.ReportName, this.ReportingServiceUrl, this.FormatReportPathFilename(), sbParameters.ToString(), methodCode.ToString()));

                this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - Test code built", ImagePath = "/Images/16x16-Valid.png" });
                return classCode.ToString();
            }
            finally {
                this.MainApp.LogMessage("Info","ParseNode exited"); 
                Mouse.OverrideCursor = null; }
        }
        private NodeDetails RetrieveExistingNodeDetails(string xPath, NodeDetails defaultNodeDetails)
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","RetrieveExistingNodeDetails entered"); 

                if (this.LstNodeDetails == null) return defaultNodeDetails;

                if (this.LstNodeDetails.Where(nde => nde.XPath == xPath && nde.ClassName == defaultNodeDetails.ClassName).Count() > 0)
                {
                    return this.LstNodeDetails.Where(nde => nde.XPath == xPath && nde.ClassName == defaultNodeDetails.ClassName).FirstOrDefault();
                }

                return defaultNodeDetails; // not found
            }
            finally {
                this.MainApp.LogMessage("Info","RetrieveExistingNodeDetails exited"); 
                Mouse.OverrideCursor = null; }
        }
        private string FormatReportPathFilename()
        {
            this.ReportPath = this.ReportPath.Replace(@"\", @"/");
            if (this.ReportPath != string.Empty && !this.ReportPath.EndsWith(@"/")) this.ReportPath += @"/";
            if (this.ReportPath != string.Empty && !this.ReportPath.StartsWith(@"/")) this.ReportPath = @"/" + this.ReportPath;
            return this.ReportPath = this.ReportPath + this.ReportName;
        }
        #endregion

        #region Public Methods
        public void DetermineRibbonBarMenuItemsStatus()
        {
            try
            {
                this.MainApp.LogMessage("Info","DetermineRibbonBarMenuItemsStatus entered"); 

                // work out what can be enabled\disabled in ribbonbar
                bool reportMenuItems = false;
                this.MenuArgs.Clear();

                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnSaveParameters", IsRibbonButtonEnabled = false });

                if (this.ReportName != string.Empty) reportMenuItems = true;

                // get selected node - check for assertions before enabling  'generate code' button
                // this.btnReportCreateTests.IsEnabled = prop.TreeNodeAssertionDetails.Count > 0 ? true : false;

                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnReportGerParams", IsRibbonButtonEnabled = reportMenuItems });
                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnReportCallReport", IsRibbonButtonEnabled = reportMenuItems });

                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnCutPasteCode", IsRibbonButtonEnabled = false }); // wrong tab

                //bool assertionsFound = true;
                //if (this.lstBoxAssertions.Items.Count == 0) assertionsFound = false;
                //this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnReportCreateTests", IsRibbonButtonEnabled = assertionsFound });

                this.RibbonBarItemUpdated(this, MenuArgs);
            }
            finally
            {
                this.MainApp.LogMessage("Info","DetermineRibbonBarMenuItemsStatus exited"); 
            }
        }
        #endregion     
    }
}
